#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <functional>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include "protocol.hpp"

namespace server
{
    enum
    {
        USAGE_ERR = 1,
        SOCKET_ERR,
        BIND_ERR,
        LISTEN_ERR
    };

    static const uint16_t gport = 8080;
    static const int gbacklog = 5;

    using func_t = std::function<bool(const HttpRequest &, HttpResponse &)>;

    class HttpServer
    {
    public:
        HttpServer(func_t func, const uint16_t &port = gport)
            : _func(func), _listensock(-1), _port(port)
        {
        }

        void initServer()
        {
            _listensock=socket(AF_INET,SOCK_STREAM,0);
            if(_listensock<0)
            {
                exit(SOCKET_ERR);
            }

            struct sockaddr_in local;
            local.sin_family=AF_INET;
            local.sin_port=htons(_port);
            // 和绑定 0.0.0.0效果一致
            local.sin_addr.s_addr=INADDR_ANY;
            socklen_t len = sizeof(local);
            if(bind(_listensock,(struct sockaddr *)&local,len)<0)
            {
                exit(BIND_ERR);
            }
            if(listen(_listensock,gbacklog)<0)
            {
                exit(LISTEN_ERR);
            }
            
        }
        void handlertHttp(int sock)
        {
             // 1. 读到完整的http请求
            // 2. 反序列化
            // 3. httprequst, httpresponse, _func(req, resp)
            // 4. resp序列化
            // 5. send
            char buffer[4096];
            HttpRequest req;
            HttpResponse resp;
            size_t n = recv(sock, buffer, sizeof(buffer)-1, 0); // 大概率我们直接就能读取到完整的http请求
            if(n > 0)
            {
                buffer[n] = 0;
                req.inbuffer = buffer;
                req.parse();
                _func(req, resp); // req -> resp
                send(sock, resp.outbuffer.c_str(), resp.outbuffer.size(), 0);
            }
        }
        void start()
        {
            for(;;)
            {
                struct sockaddr_in peer;
                socklen_t len  = sizeof(peer);
                int sock = accept(_listensock,(struct sockaddr *)&peer,&len);
                if(sock<0)
                {
                    continue;
                }
                // 采用多进程方式
                pid_t pid = fork();
                if(pid == 0) // child
                {
                    close(_listensock);
                    if(fork()>0)
                    {
                        exit(0);
                    }
                    handlertHttp(sock);
                    close(sock);
                    exit(0);
                }
                close(sock);
                // father
                waitpid(pid,nullptr,0);
            }
        }
        ~HttpServer()
        {}
    private:
        int _listensock;
        uint16_t _port;
        func_t _func;
    };
}
